package fieldmaps.files;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.triangulate.VoronoiDiagramBuilder;

import fieldmaps.database.DatabaseGenericMap;
import fieldmaps.database.DatabaseVoronoiMap;
import fieldmaps.types.VoronoiMapInfo;

public class LoadVoronoiMapFromFile implements ILoadMapFromFile {

	private static Logger LOGGER = Logger.getLogger(LoadVoronoiMapFromFile.class);
	
	/**
	 * Levanta un header y un archivo con la informacion corespondiente a un
	 * mapa de Voronoi.
	 * 
	 */
	@Override
	public DatabaseGenericMap createMapFromFile(String filename, String mapName)
			throws IOException {
		VoronoiMapInfo voronoiInfo = readHeader(filename + ".hdr"); // Se lee el header
		DatabaseGenericMap map = DatabaseVoronoiMap.createMap(mapName,voronoiInfo); // Se crea el mapa en la base de datos
		readData(map, voronoiInfo, filename + ".voronoi");
		return map;
	}

	/**
	 * Se carga la informacion en la base de datos. El archivo es de texto,
	 * contiene las coordenadas de los puntos seguidas por el valor asociado,
	 * separadas por espacio.
	 * 
	 * @param map
	 * @param voronoiInfo
	 * @param filename
	 * @throws IOException
	 */
	private void readData(DatabaseGenericMap map, VoronoiMapInfo voronoiInfo,
			String filename) throws IOException {
		FileInputStream file = new FileInputStream(filename);
		InputStreamReader stream = new InputStreamReader(file);
		BufferedReader reader = new BufferedReader(stream);
		VoronoiDiagramBuilder voronoiDiagramBuilder = new VoronoiDiagramBuilder();
		List<VoronoiPoint> voronoiPoints = new ArrayList<VoronoiPoint>();
		GeometryFactory geometryFactory = new GeometryFactory();
		String line = null;

		System.out.println("Parsing the data...");

		while ((line = reader.readLine()) != null) {
			String[] values = line.split(" ");
			if (values.length > 2) {
				voronoiPoints.add(new VoronoiPoint(new Coordinate(Double
						.valueOf(values[0]), Double.valueOf(values[1])),
						Integer.valueOf(values[2])));
			}
		}
		
		//TODO: Provisional, mejorar esto!
		List<Coordinate> coordinates = new ArrayList<Coordinate>();
		for( VoronoiPoint vp : voronoiPoints )	{
			coordinates.add(vp.coordinate);
		}
		voronoiDiagramBuilder.setSites(coordinates);
		
		voronoiDiagramBuilder.setClipEnvelope(new Envelope(
				voronoiInfo.getxUpperLeft(),
				voronoiInfo.getxLowerRight(), 
				voronoiInfo.getyUpperLeft() ,
				voronoiInfo.getyLowerRight()));
		
		Geometry geometry = voronoiDiagramBuilder.getDiagram(geometryFactory);
		
		for (int i = 0; i < geometry.getNumGeometries(); i++) {
			Geometry aux = geometry.getGeometryN(i);
			try {
				map.addCell(aux.getCoordinates(), voronoiPoints.get(i).value);
			} catch (SQLException e) {
				System.out.println("Error creating data in the database.");
			}
		}
		System.out.println("Parsing data OK");
	}

	private VoronoiMapInfo readHeader(String filename) throws IOException {
		VoronoiMapInfo voronoiInfo = new VoronoiMapInfo();
		FileInputStream file = new FileInputStream(filename);
		InputStreamReader stream = new InputStreamReader(file);
		BufferedReader reader = new BufferedReader(stream);
		String line = null;

		System.out.println("Parsing the Header...");

		Map<String, String> properties = new HashMap<String, String>();
		while ((line = reader.readLine()) != null) {
			String[] values = line.split("\t");
			if (values.length > 1) {
				properties.put(values[0], values[1]);
			}
		}
		voronoiInfo.setxLowerRight(Double.valueOf(properties.get("xLowerRight")));
		voronoiInfo.setyLowerRight(Double.valueOf(properties.get("yLowerRight")));
		voronoiInfo.setxUpperLeft(Double.valueOf(properties.get("xUpperLeft")));
		voronoiInfo.setyUpperLeft(Double.valueOf(properties.get("yUpperLeft")));

		LOGGER.info("Parsing header OK");
		return voronoiInfo;
	}
	
}

class VoronoiPoint {
	public Coordinate coordinate;
	public Integer value;

	public VoronoiPoint(Coordinate coordinate, Integer value) {
		this.coordinate = coordinate;
		this.value = value;
	}
}
